package org.jcs.simulation.neds.gui;

import com.sun.j3d.utils.universe.*;
import com.sun.j3d.utils.geometry.*;
import javax.media.j3d.*;
import javax.vecmath.*;

import org.jcs.simulation.neds.Dimensions;

import java.awt.GraphicsConfiguration;
import java.awt.BorderLayout;
import java.applet.Applet;

public class NedEngine3D extends Applet{
	public TransformGroup getPatchRotateGroup() {
		return patchRotateGroup;
	}
	private Dimensions dimensions;
	private BranchGroup patchGroup;
	private TransformGroup patchRotateGroup;
        private TransformGroup patchPosGroupX;
        private TransformGroup patchPosGroupY;
        private TransformGroup patchPosGroupZ;
        private TransformGroup patchRotateGroupX;
        private TransformGroup patchRotateGroupY;
        private TransformGroup patchRotateGroupZ;
	private BranchGroup contents;
	private int patchPosition = 0;
	SimpleUniverse universe;
        PositionInterpolator posX;
        PositionInterpolator posY;
        PositionInterpolator posZ;
        RotationInterpolator rotatorX;
        RotationInterpolator rotatorY;
        RotationInterpolator rotatorZ;
        Alpha posAlphaX;
        Alpha posAlphaY;
        Alpha posAlphaZ;
        Alpha rotationAlphaX;
        Alpha rotationAlphaY;
        Alpha rotationAlphaZ;
	private int lastMove = 0;
        private int lastDirection=13;
        private float moveAmountX = 0f;
        private float moveAmountY = 0f;
        private float moveAmountZ = 0f;
        private float posAmountX = 0f;
        private float posAmountY = 0f;
        private float posAmountZ = 0f;
	
	public NedEngine3D(Dimensions dimensionsSet)
	{
		dimensions = dimensionsSet;
		setLayout(new BorderLayout());
		GraphicsConfiguration config = SimpleUniverse.getPreferredConfiguration();
		Canvas3D canvas = new Canvas3D(config);
		add("Center", canvas);
		contents = new BranchGroup();
		patchGroup = new BranchGroup();

		universe = new SimpleUniverse(canvas);
		universe.getViewingPlatform().setNominalViewingTransform();
		contents.addChild(patchGroup);

                posAlphaX = new Alpha(1,300);
                posAlphaY = new Alpha(1,300);
                posAlphaZ = new Alpha(1,300);

                rotationAlphaX = new Alpha(1,300);
                rotationAlphaY = new Alpha(1,300);
                rotationAlphaZ = new Alpha(1,300);

                patchPosGroupX = new TransformGroup();
                patchPosGroupX.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE);

                patchPosGroupY = new TransformGroup();
                patchPosGroupY.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE);

                patchPosGroupZ = new TransformGroup();
                patchPosGroupZ.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE);

                patchRotateGroupX = new TransformGroup();
                patchRotateGroupX.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE);

		patchRotateGroupY = new TransformGroup();
                patchRotateGroupY.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE);

                patchRotateGroupZ = new TransformGroup();
                patchRotateGroupZ.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE);
                patchRotateGroupZ.setCapability(TransformGroup.ALLOW_CHILDREN_EXTEND);
		patchRotateGroupZ.setCapability(TransformGroup.ALLOW_CHILDREN_WRITE);

                BoundingSphere zone = new BoundingSphere();

                posX =
                   new PositionInterpolator(
                     posAlphaX,patchPosGroupX);
                posX.setSchedulingBounds(zone);
                posX.setEndPosition(0);


                posY =
                   new PositionInterpolator(
                     posAlphaY,patchPosGroupY);
                posY.setSchedulingBounds(zone);
                posY.setEndPosition(0);

                Transform3D myAxis = posX.getTransformAxis();
                myAxis.rotZ(-Math.PI/2.0d);
                posY.setTransformAxis(myAxis);

                posZ =
                   new PositionInterpolator(
                     posAlphaZ,patchPosGroupZ);
                posZ.setSchedulingBounds(zone);
                posZ.setEndPosition(0);

                myAxis = posY.getTransformAxis();
                myAxis.rotY(Math.PI/2.0d);
                posZ.setTransformAxis(myAxis);

                rotatorX =
                   new RotationInterpolator(
                     rotationAlphaX,patchRotateGroupX);
                rotatorX.setSchedulingBounds(zone);

                rotatorY =
                   new RotationInterpolator(
                     rotationAlphaY,patchRotateGroupY);
                rotatorY.setSchedulingBounds(zone);
                myAxis = rotatorX.getTransformAxis();
                myAxis.rotZ(-Math.PI/2.0d);
                rotatorY.setTransformAxis(myAxis);

                rotatorZ =
                   new RotationInterpolator(
                     rotationAlphaZ,patchRotateGroupZ);
                rotatorZ.setSchedulingBounds(zone);
                myAxis = rotatorY.getTransformAxis();
                myAxis.rotX(-Math.PI/2.0d);
                rotatorZ.setTransformAxis(myAxis);

                patchGroup.addChild(patchPosGroupX);
                patchPosGroupX.addChild(posX);
                patchPosGroupX.addChild(patchPosGroupY);
                patchPosGroupY.addChild(posY);
                patchPosGroupY.addChild(patchPosGroupZ);
                patchPosGroupZ.addChild(posZ);
                patchPosGroupZ.addChild(patchRotateGroupX);
                patchRotateGroupX.addChild(rotatorX);
                patchRotateGroupX.addChild(patchRotateGroupY);
                patchRotateGroupY.addChild(rotatorY);
                patchRotateGroupY.addChild(patchRotateGroupZ);
                patchRotateGroupZ.addChild(rotatorZ);

	}
	public Dimensions getDimensions() {
		return dimensions;
	}
	public BranchGroup getContents() {
		return contents;
	}
	public SimpleUniverse getUniverse() {
		return universe;
	}
	public void run()
	{
		universe.addBranchGraph(contents);
	}
	public void addBranch(BranchGroup group)
	{
		group.setCapability(BranchGroup.ALLOW_DETACH);
		patchRotateGroupZ.addChild(group);
	}
	public void cameraUpdate(int x, int moveSize)
	{
                TransformGroup tg = universe.getViewingPlatform().getViewPlatformTransform();
		Transform3D tf = new Transform3D();
		Transform3D tf2 = new Transform3D();
		Transform3D rt = new Transform3D();
		tg.getTransform(tf);
		//patchRotateGroup.getTransform(tf2);
		Vector3f c = new Vector3f();
		tf.get(c);

                float moveVal;
                if(lastDirection == 0)
                    posAmountX += posAlphaX.value()*.1f*lastMove;
                else if(lastDirection == 1)
                    posAmountX -= posAlphaX.value()*.1f*lastMove;
                else if(lastDirection == 2)
                    posAmountY += posAlphaY.value()*.1f*lastMove;
                else if(lastDirection == 3)
                    posAmountY -= posAlphaY.value()*.1f*lastMove;
                else if(lastDirection == 4)
                    posAmountZ -= posAlphaZ.value()*.1f*lastMove;
                else if(lastDirection == 5)
                    posAmountZ += posAlphaZ.value()*.1f*lastMove;
                else if(lastDirection == 6)
                    moveAmountX += rotationAlphaX.value()*(float)(2*(lastMove)*Math.PI/180);
                else if (lastDirection == 7)
                    moveAmountX += -rotationAlphaX.value()*(float)(2*(lastMove)*Math.PI/180);
                else if(lastDirection == 9)
                    moveAmountY += rotationAlphaY.value()*(float)(2*(lastMove)*Math.PI/180);
                else if (lastDirection == 8)
                    moveAmountY += -rotationAlphaY.value()*(float)(2*(lastMove)*Math.PI/180);
                else if(lastDirection == 10)
                    moveAmountZ += rotationAlphaZ.value()*(float)(2*(lastMove)*Math.PI/180);
                else if (lastDirection == 11)
                    moveAmountZ += -rotationAlphaZ.value()*(float)(2*(lastMove)*Math.PI/180);

                if(x==0)
                {
                    posX.setStartPosition(posAmountX);
                    posX.setEndPosition(posAmountX+.1f*moveSize);
                    posAlphaX.setStartTime(System.currentTimeMillis());
                    posAlphaX.setTriggerTime(1);
                }
                else if(x==1)
                {
                    posX.setStartPosition(posAmountX);
                    posX.setEndPosition(posAmountX-.1f*moveSize);
                    posAlphaX.setStartTime(System.currentTimeMillis());
                    posAlphaX.setTriggerTime(1);
                }
                else if(x == 2)
                {
                    posY.setStartPosition(posAmountY);
                    posY.setEndPosition(posAmountY+.1f*moveSize);
                    posAlphaY.setStartTime(System.currentTimeMillis());
                    posAlphaY.setTriggerTime(1);
                }
                else if(x==3)
                {
                    posY.setStartPosition(posAmountY);
                    posY.setEndPosition(posAmountY-.1f*moveSize);
                    posAlphaY.setStartTime(System.currentTimeMillis());
                    posAlphaY.setTriggerTime(1);
                }
		else if(x == 4)
                {
                    posZ.setStartPosition(posAmountZ);
                    posZ.setEndPosition(posAmountZ-.1f*moveSize);
                    posAlphaZ.setStartTime(System.currentTimeMillis());
                    posAlphaZ.setTriggerTime(1);
                }
                else if(x==5)
                {
                    posZ.setStartPosition(posAmountZ);
                    posZ.setEndPosition(posAmountZ+.1f*moveSize);
                    posAlphaZ.setStartTime(System.currentTimeMillis());
                    posAlphaZ.setTriggerTime(1);
                }
		else if(x==6)
                {
                    rotatorX.setMinimumAngle(moveAmountX);
                    rotatorX.setMaximumAngle(moveAmountX+(float)(2*(moveSize)*Math.PI/180));
                    rotationAlphaX.setStartTime(System.currentTimeMillis());
                    rotationAlphaX.setTriggerTime(1);
                }
                else if(x==7)
                {
                    rotatorX.setMinimumAngle(moveAmountX);
                    rotatorX.setMaximumAngle(moveAmountX-(float)(2*(moveSize)*Math.PI/180));
                    rotationAlphaX.setStartTime(System.currentTimeMillis());
                    rotationAlphaX.setTriggerTime(1);
                }
		else if(x==8)
                {
                    rotatorY.setMinimumAngle(moveAmountY);
                    rotatorY.setMaximumAngle(moveAmountY-(float)(2*(moveSize)*Math.PI/180));
                    rotationAlphaY.setStartTime(System.currentTimeMillis());
                    rotationAlphaY.setTriggerTime(1);
                }
		else if(x==9)
                {
                    rotatorY.setMinimumAngle(moveAmountY);
                    rotatorY.setMaximumAngle(moveAmountY+(float)(2*(moveSize)*Math.PI/180));
                    rotationAlphaY.setStartTime(System.currentTimeMillis());
                    rotationAlphaY.setTriggerTime(1);
                }
		else if(x==10)
                {
                    rotatorZ.setMinimumAngle(moveAmountZ);
                    rotatorZ.setMaximumAngle(moveAmountZ+(float)(2*(moveSize)*Math.PI/180));
                    rotationAlphaZ.setStartTime(System.currentTimeMillis());
                    rotationAlphaZ.setTriggerTime(1);
                }
		else if(x==11)
                {
                    rotatorZ.setMinimumAngle(moveAmountZ);
                    rotatorZ.setMaximumAngle(moveAmountZ-(float)(2*(moveSize)*Math.PI/180));
                    rotationAlphaZ.setStartTime(System.currentTimeMillis());
                    rotationAlphaZ.setTriggerTime(1);
                }
                lastMove = moveSize;
                lastDirection = x;

                if(x==12)
                {
                    posAmountX=0;
                    posAmountY=0;
                    posAmountZ=0;
                    moveAmountX=0;
                    moveAmountY=0;
                    moveAmountZ=0;
                    lastMove=0;
                    lastDirection=13;
                    posX.setStartPosition(0);
                    posX.setEndPosition(0);
                    posY.setStartPosition(0);
                    posY.setEndPosition(0);
                    posZ.setStartPosition(0);
                    posZ.setEndPosition(0);
                    rotatorX.setMinimumAngle(0);
                    rotatorX.setMaximumAngle(0);
                    rotatorY.setMinimumAngle(0);
                    rotatorY.setMaximumAngle(0);
                    rotatorZ.setMinimumAngle(0);
                    rotatorZ.setMaximumAngle(0);
                    posAlphaX.setStartTime(System.currentTimeMillis());
                    posAlphaX.setTriggerTime(1);
                    posAlphaY.setStartTime(System.currentTimeMillis());
                    posAlphaY.setTriggerTime(1);
                    posAlphaZ.setStartTime(System.currentTimeMillis());
                    posAlphaZ.setTriggerTime(1);
                    rotationAlphaX.setStartTime(System.currentTimeMillis());
                    rotationAlphaX.setTriggerTime(1);
                    rotationAlphaY.setStartTime(System.currentTimeMillis());
                    rotationAlphaY.setTriggerTime(1);
                    rotationAlphaZ.setStartTime(System.currentTimeMillis());
                    rotationAlphaZ.setTriggerTime(1);

                }
	}
	public void addPatch(Material material)
	{
		Transform3D tf = new Transform3D();
		TransformGroup tg = new TransformGroup();
		float width = new Float(dimensions.getWidth());
		float height = new Float(dimensions.getHeight());
		float x_unit = 2.1f/dimensions.getWidth();
		float y_unit = 1.1f/dimensions.getHeight();
		int x_pos = patchPosition%dimensions.getWidth();
		int y_pos = patchPosition/dimensions.getHeight();
		float x_start = (-0.5f*(dimensions.getWidth()))*x_unit+x_unit/2;
		float y_start = (0.5f*(dimensions.getHeight()))*y_unit-y_unit/2;
		Vector3f pos = new Vector3f(
				x_start+x_pos*x_unit,
				y_start-y_pos*y_unit,
				0.0f);
		tf.setTranslation(pos);
		tg.setTransform(tf);
		Appearance appearance = new Appearance();
		appearance.setMaterial(material);
		tg.addChild(
				new Box(
				1.0f/dimensions.getWidth(),
				1.0f/(2*dimensions.getHeight()),
				0.001f, 
				appearance)
		);
		patchRotateGroupZ.addChild(tg);
		patchPosition++;
	}

}
